﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <unordered_map>
#include <map>
#include <string>
#include <vector>
#include <set>
#include <list>
#include <stack>
#include <queue>

using namespace std;

#include "string.h"
// ===============  统一的列表初始化 =============== 

// 1. ｛｝初始化

//struct MyStruct
//{
//	int a;
//	int b;
//};
//
//int main()
//{
//	int arr[3] = { 1,2,3 };
//	for (int i = 0; i < 3; i++)
//	{
//		cout << arr[i] << " ";
//	}
//	cout << endl;
//
//	MyStruct sct = { 1, 2 };
//	cout << sct.a << " " << sct.b << endl;
//
//	return 0;
//}

//class MyClass
//{
//public:
//	MyClass(int a = 0, int b = 0)
//		:_a(a)
//		,_b(b)
//	{
//		cout << "调用了MyClass的默认构造函数" << endl;
//	}
//
//	int _a;
//	int _b;
//};
//
//int main()
//{
//	int a = { 1 }; // 内置类型
//	cout << a << endl;
//
//	// 老式写法
//	MyClass c1(1, 2);
//	cout << c1._a << " " << c1._b << endl;
//
//	// C++11
//	MyClass c2 = { 1,2 }; // 类对象
//	cout << c2._a << " " << c2._b << endl;
//
//	return 0;
//}

// 从上看出，C++11还支持多参数隐式类型转换

//int main()
//{
//	int a{ 1 }; // 内置类型
//	cout << a << endl;
//
//	MyClass c{ 1,2 };
//	cout << c._a << " " << c._b << endl;
//
//	return 0;
//}


// 2. initializer_list

//int main()
//{
//	auto a = { 1,2,3 };
//	cout << typeid(a).name() << endl;
//	return 0;
//}

//int main()
//{
//	vector<int> v = { 1,2,3,4,5,6 };
//	// 当然也可以省略括号初始化
//	vector<int> v2{ 1,2,3,4,5,6 };
//
//	for (auto e : v)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	for (auto e : v2)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	return 0;
//}

//int main()
//{
//	// 这里{"苹果", "apple"}会先初始化构造一个pair对象
//	// pair容器底层也支持initializer_list作为参数的构造函数
//	map<string, string> m = { {"苹果", "apple"}, {"香蕉", "banana"},{"西瓜", "watermelon"} };
//	for (auto e : m)
//	{
//		cout << e.first << " " << e.second << endl;
//	}
//	cout << endl;
//	return 0;
//}

// ===================== decltype =================

//const int ci = 0;
//const int& cj = ci;
//decltype(ci) x = 0; // x的类型是const int
//decltype(cj) y = x; // y的类型是const int&，y是x的别名
//decltype(cj) z;     // erro：z是一个引用，必须初始化

//int func()
//{
//	int x = 1;
//	++x;
//	return x;
//}
//
//int main()
//{
//	decltype(func()) d; // d的类型是func函数的返回值：int
//	decltype(func() + 1) x; // int + 1还是int类型
//	return 0;
//}

//int main()
//{
//	int i = 1;
//	int* p = &i;
//	int& r = i;
//	
//	decltype(i + i) a; // a是int类型
//	decltype(r + 0) b; // b是int类型
//	decltype(*p) c; // erro，c是int&，必须初始化
//}


//int main()
//{
//	int i = 1;
//	int c = 1;
//	decltype((i)) d = 11; // erro，d是int&，必须显示初始化
//	decltype(i) e; // 正确，e是一个未初始化的int类型
//	
//	cout << typeid(d).name() << endl;
//	return 0;
//}

// =================== 范围for ==========================

//int main()
//{
//	vector<int> v = { 1,2,3,4,5,6 };
//	for (auto e : v)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	// 范围for遍历
//	auto vit = v.begin();
//	while (vit != v.end())
//	{
//		cout << *vit << " ";
//		++vit;
//	}
//	cout << endl;
//	return 0;
//}

// ============================= 左值引用和右值引用 ==============================

// 要想搞懂左值引用和右值引用，首先要得明白什么是左值和右值
// 很多人认为在赋值符号左边的就是左值，在赋值符号右边的就是右值
// 这其实并不完全正确，比如：

//int main()
//{
//	int a = 1; // a是左值
//	int b = a; // a又变成右值？
//}

// 以上a到底是左值还是右值？其实是左值。
// 这里给一个简单粗暴的判断方法：可以取地址就是左值
// 举个例子，以下是常见的左值

//int main()
//{
//	// 以下的p、b、c、*p都是左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = 2;
//	
//	cout << "p的地址：" << &p << endl;
//	cout << "*p的地址：" << &(*p) << endl;
//	cout << "b的地址：" << &b << endl;
//	cout << "c的地址：" << &c << endl;
//
//	return 0;
//}

// 那么什么是右值？
// 右值通过是一个表达式，就这么说吧，只要不能取地址的就是右值。常见的右值有：字面常量、表达式返回值，函数返回值(临时对象返回)等
// 右值可以出现在赋值符号的右边，但是不能出现出现在赋值符号的左边
// 举个例子吧

//double Min(double x, double y)
//{
//	return x > y ? y : x;
//}

//int main()
//{
//	// 以下几个都是常见的右值
//	10;        // 字面常量
//	1 + 2;     // 表达式返回值
//	Min(1, 2); // 函数返回值
//	
//	// 不能对右值取地址
//	cout << &10 << endl;
//	cout << &(1 + 2) << endl;
//	cout << &(Min(1, 2)) << endl;
//
//	return 0;
//}

// 既然我们知道了如何区分左值和右值，接下来我们来看什么是左值引用和右值引用
// 大家只要记住一句话，不管是什么引用，都是取别名。左值引用就是对左值取别名，右值引用就是对右值取别名
// 首先先来看看左值引用的例子：
//int main()
//{
//	// 以下的p、b、c、*p都是左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = 2;
//
//	// 以下几个是对上面左值的左值引用
//	int*& rp = p;
//	int& rb = b;
//	const int& rc = c;
//	int& pvalue = *p;
//
//	return 0;
//}

// 由上可以看出，左值引用就是C++刚入门学的那个引用，唯一有区别的还是右值引用
// 右值引用的写法就比左值引用多一个&
//int main()
//{
//	// 以下几个都是常见的右值
//	10;
//	1.1 + 2.2;
//	Min(1.1, 2.2);
//
//	// 以下几个都是对右值的右值引用
//	int&& rr1 = 10;
//	double&& rr2 = 1 + 2;
//	double&& rr3 = Min(1, 2);
//
//	return 0;
//}

// 左值引用 vs 右值引用 
// 问题1：左值引用能否给右值取别名？

//int main()
//{
//	int& a = 1;
//	int& b = 1 + 1;
//	double& c = Min(1.1, 2.2);
//
//	return 0;
//}

// 正常来说是不行的，但因为右值都具有常属性，因此用const引用即可

//int main()
//{
//	const int& a = 1;
//	const int& b = 1 + 1;
//	const double& c = Min(1.1, 2.2);
//
//	return 0;
//}

// 问题2：右值引用能否引用左值？

//int main()
//{
//	// 以下的p、b、c、*p都是左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = 2;
//
//	int&& x = p;
//	int&& y = *p;
//	int&& z = c;
//	int&& q = b;
//	
//	return 0;
//}

// 编译器已经给出很明确的报错信息了：无法将右值引用绑定到左值
// 但右值引用可以引用move以后的左值
//int main()
//{
//	// 以下的p、b、c、*p都是左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = 2;
//
//	int&& x = move(p);
//	int&& y = move(*p);
//	// int&& z = move(c);
//	int&& q = move(b);
//
//	return 0;
//}
// move调用告诉编辑器：有一个左值，希望像一个右值一样处理它。我们必须认识到，调用move就意味着承诺：
// move() 的主要作用是显式地标识对象为右值，以便编译器能够选择调用移动语义相关的操作，而不是进行拷贝操作。

//int main()
//{
//	vector<int> v = { 1,2,3 };
//	vector<int> rv = move(v);
//
//	v = { 1,1,1,1 };
//
//	cout << v.size() << endl;
//	return 0;
//}

//int main()
//{
//	const int a = 1;
//	int b = move(a);
//	cout << b << endl;
//}

// 是否构成函数重载
//void func(const int& r)
//{
//	cout << "void func(const int& r)" << endl;
//}
//
//void func(int&& r)
//{
//	cout << "void func(int&& r)" << endl;
//}
//
//int main()
//{
//	int a = 0;
//	func(a);
//	func(0);
//	return 0;
//}

// 右值引用使用场景和意义
// 前面我们可以看到左值引用既可以引用左值也可以通过const引用引用右值，那为什么C++11还要提出右值引用呢？难道C++委员会又在划水？
// 既然提出了就一定是为了解决左值引用存在的缺陷，那么我们可以通过分析左值引用的使用场景及核心价值来推断。
// 使用场景：1. 做输出型参数 2. 做返回值
// 核心价值：都是减少拷贝

// 而我们知道，左值引用做返回值是有一定的缺陷的！
//   

//wj::string Myfunc()
//{
//	wj::string str("hello world!");
//	return str;
//}
//
//int main()
//{
//	wj::string s = Myfunc();
//
//	return 0;
//}

// str是局部对象，出了func函数作用域，对象销毁，那么就不能用左值引用返回，那么按照惯例只能使用传值返回
// 而传值返回是有代价的，对于较大的对象（如大型结构体、类对象等），
// 可能会导致较大的性能开销，因为它需要在内存中复制整个对象的内容。

// 以上代码本来应该是两次拷贝构造，但对于一行的两次拷贝构造，新一点的编译器会优化成一次拷贝构造。
// 虽然优化成一次拷贝构造，但是拷贝需要赋值整个对象的内容，但是有很大的消耗

// 因此，我们可以使用右值引用和移动语义解决上述问题：在bit::string中增加移动构造，**移动构造本质是将参数右值的资源窃取过来**，
// 占位已有，那么就不用做深拷贝了，所以它叫做移动构造，就是窃取别人的资源来构造自己。

// 移动构造代码。。。

// Myfunc的返回值是一个右值，用这个右值构造s，如果既有拷贝构造，也有移动构造，那么编译器就会选择最匹配的参数调用

// 接下来再看，如果不是一行的两次拷贝构造，那么编译器就会真正进行两次深拷贝

//wj::string Myfunc()
//{
//	wj::string str("hello world!");
//	return str;
//}
//
//int main()
//{
//	wj::string s;
//
//	s = Myfunc();
//
//	return 0;
//}

//int main()
//{
//    int&& a = 0;
//    cout << &a << endl; //右值引用本身是可以取地址，因此a是左值
//
//    return 0;
//}

//int main()
//{
//	list<wj::string> lt;
//	wj::string s("1111");
//
//	lt.push_back(s); //调用string的拷贝构造
//
//	lt.push_back("2222");             //调用string的移动构造
//	lt.push_back(wj::string("3333")); //调用string的移动构造
//	lt.push_back(std::move(s));       //调用string的移动构造
//	return 0;
//
//	cout << &"11111111111" << endl;
//	return 0;
//}
    
// =================== 完美转发 ==============================
// 在模板中的`&&`不代表右值引用，而是万能引用，其既能接收任意类型的左值和右值。
// * 如果传入的实参是左值，那么编译器就会将模板实例化为左值引用，也称做引用折叠。
// * 如果传入的实参是右值，那么编译器就会将模板实例化为右值引用。


//void Fun(int& x) 
//{ 
//    cout << "左值引用" << endl; 
//}
//
//void Fun(const int& x) 
//{ 
//    cout << "const 左值引用" << endl; 
//}
//
//void Fun(int&& x) 
//{ 
//    cout << "右值引用" << endl; 
//}
//void Fun(const int&& x) 
//{ 
//    cout << "const 右值引用" << endl; 
//}
//
//template<typename T>
//void PerfectForward(T&& t)
//{
//    Fun(t);
//}
//
//int main()
//{
//    PerfectForward(10); // 右值
//
//    int a;
//    PerfectForward(a); // 左值
//
//    PerfectForward(std::move(a)); // 右值
//
//    const int b = 8;
//    PerfectForward(b); // const 左值
//
//    PerfectForward(std::move(b)); // const 右值
//
//    return 0;
//}
// 

// 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力，
// 但是引用类型的唯一作用就是限制了接收的类型，后续使用中都退化成了左值，
// 我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发


//void Fun(int& x) 
//{ 
//    cout << "左值引用" << endl; 
//}
//
//void Fun(const int& x) 
//{ 
//    cout << "const 左值引用" << endl; 
//}
//
//void Fun(int&& x) 
//{ 
//    cout << "右值引用" << endl; 
//}
//void Fun(const int&& x) 
//{ 
//    cout << "const 右值引用" << endl; 
//}
//
//template<typename T>
//void PerfectForward(T&& t)
//{
//    Fun(forward<T>(t));
//}
//
//int main()
//{
//    PerfectForward(10); // 右值
//
//    int a;
//    PerfectForward(a); // 左值
//
//    PerfectForward(std::move(a)); // 右值
//
//    const int b = 8;
//    PerfectForward(b); // const 左值
//
//    PerfectForward(std::move(b)); // const 右值
//
//    return 0;
//}

// =============== lambda表达式 =======================


//void func()
//{
//    cout << "void func()" << endl;
//}
//
//struct A
//{
//    void operator()()
//    {
//        func();
//    }
//};
//
//int main()
//{
//    A a;
//    a();
//    return 0;
//}
//


//int main()
//{
//    // 在lambda表达式的函数体中，我们不能使用除了参数列表中的变量。
//    int x = 0;
//    auto p = [=]()mutable ->void { 
//        // func();
//        cout << c << endl;
//         };
//    
//    p();
//    int c = 1;
//    return 0;
//}

//int main()
//{
//    int a = 3;
//    []() {cout << a << endl; };
//    
//    return 0;
//}


//struct func
//{
//    void operator()(int x, int y)
//    {
//        cout << "operator()(int x, int y)" << endl;
//    }
//};
//
//int main()
//{
//    int a = 3;
//    int b = 3;
//
//    // 仿函数对象实例化
//    func f;
//    f(a, b);
//
//    // lambda表达式
//    auto e = [=](int x, int y) {
//        cout << "[=](int x, int y)" << endl;
//    };
//    e(a, b);
//
//    return 0;
//}


//int main()
//{
//    auto e = []() { ;};
//    
//    cout << typeid(e).name() << endl;
//
//    return 0;
//}

// ============== 可变模板参数 ===================


// 我们用一个省略号（三个点）指出一个模板参数或者函数参数表示一个包。
// 在一个模板参数列表中，class...或者typename...指出接下来的参数表示0个或者多个类型的列表；
// 一个类型名后面跟一个省略号表示0个或者多个给定类型的非类型参数的列表。在函数参数列表中，如果一个
// 参数的类型是一个模板参数包，则此参数也是一个函数参数包


// Args是一个模板参数包，表示0个或多个模板类型参数
// rest是一个函数参数包，表示0个或多个函数参数
//template <typename T, typename... Args>
//void func(const T& t, const Args& ... rest)
//{
//    cout << sizeof...(rest) << endl;
//}
//
//int main()
//{
//    int i = 0;
//    double d = 3.14;
//    string s = "hello world!";
//    func(i, s, 42, d); // 包中有三个参数，分别是s, 42, d
//    func(s, 42, "hi"); // 包中有两个参数，分别是42, "hi"
//    func(d, s);        // 包中有一个参数，分别是s
//    func("hi");        // 空包
//}

// 编译器则会为`func`实例化出以下四个不同的版本：

//void func(const int&, const string&, const int&, const double&);
//void func(const string&, const int&, const char[3]&);
//void func(const double&, const string&);
//void func(const char[3] &);


// 递归获取可变模板参数
//template <typename T>
//void func(const T& t)
//{
//    cout << t << " ";
//    cout << endl;
//}
//
//template <typename T, typename... Args>
//void func(const T& t, const Args& ... rest)
//{
//    cout << t << " ";
//    func(rest...);
//}
//
//int main()
//{
//    func(1); // 空包
//    func(1, 2); // 包中有一个参数，是2
//    func(1, 2, 2.2); // 包中有两个参数，是2和2.2
//    func(1, 2, 2.2, "string"); // 包中有三个参数，是2、2.2、"string"
//    // ...
//}

// 逗号表达式展开参数包

// template<class ...Args>
//void ShowList(Args... args)
//{
//    int arr[] = { args... }; //列表初始化
//    //打印参数包中的各个参数
//    for (auto e : arr)
//    {
//        cout << e << " ";
//    }
//    cout << endl;
//}
//
//int main()
//{
//    ShowList(1);
//    ShowList(1, 2);
//    ShowList(1, 2, 3);
//    return 0;
//}

//处理参数包中的每个参数
//template<class T>
//void PrintArg(const T& t)
//{
//	cout << t << " ";
//}
////展开函数
//template<class ...Args>
//void func(Args... args)
//{
//	int arr[] = { (PrintArg(args), 0)... }; //列表初始化+逗号表达式
//	cout << endl;
//}
//
//int main()
//{
//	func(1); // 空包
//    func(1, 2); // 包中有一个参数，是2
//    func(1, 2, 2.2); // 包中有两个参数，是2和2.2
//    func(1, 2, 2.2, "string"); // 包中有三个参数，是2、2.2、"string"
//
//	return 0;
//}


//template<class T>
//int PrintArg(const T& t)
//{
//	cout << t << " ";
//	return 0;
//}
////展开函数
//template<class ...Args>
//void func(Args... args)
//{
//	int arr[] = { PrintArg(args)... }; //列表初始化+逗号表达式
//	cout << endl;
//}
//
//int main()
//{
//	func(1); // 空包
//	func(1, 2); // 包中有一个参数，是2
//	func(1, 2, 2.2); // 包中有两个参数，是2和2.2
//	func(1, 2, 2.2, "string"); // 包中有三个参数，是2、2.2、"string"
//
//	return 0;
//}


// emplace接口

//class Date
//{
//public:
//    Date(int year, int month, int day)
//        :_year(year)
//        ,_month(month)
//        ,_day(day)
//    {}
//
//private:
//    int _year;
//    int _month;
//    int _day;
//};
//
//template<class ...Args>
//Date* create(Args... args)
//{
//    Date* ret = new Date(args...);
//    return ret;
//}
//
//int main()
//{
//    Date* p1 = create(2024, 4, 9);
//
//    return 0;
//}


// 包装器




// ====================  智能指针 ======================

// # 一、为什么需要智能指针
// 下面我们先分析一下下面这段程序有没有什么内存方面的问题？提示一下：注意分析MergeSort函数中的问题

//int div()
//{
//    int a, b;
//    cin >> a >> b;
//    if (b == 0)
//        throw invalid_argument("除0错误");
//    return a / b;
//}
//
//void Func()
//{
//    // 1、如果p1这里new 抛异常会如何？
//    // 2、如果p2这里new 抛异常会如何？
//    // 3、如果div调用这里又会抛异常会如何？
//    int* p1 = new int;
//    int* p2 = new int;
//    cout << div() << endl;
//    delete p1;
//    delete p2;
//}
//
//
//int main()
//{
//    try
//    {
//        Func();
//    }
//    catch (exception& e)
//    {
//        cout << e.what() << endl;
//    }
//    return 0;
//}


void MemoryLeaks()
{
    // 1.内存申请了忘记释放
    int* p1 = (int*)malloc(sizeof(int));
    int* p2 = new int;
    // 2.异常安全问题
    int* p3 = new int[10];
    Func(); // 这里Func函数抛异常导致 delete[] p3未执行，p3没被释放.
    delete[] p3;
}

// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:
    SmartPtr(T* ptr = nullptr)
        : _ptr(ptr)
    {}
    ~SmartPtr()
    {
        if (_ptr)
            delete _ptr;
    }
private:
    T* _ptr;
};
int div()
{
    int a, b;
    cin >> a >> b;
    if (b == 0)
        throw invalid_argument("除0错误");
    return a / b;
}
void Func()
{
    ShardPtr<int> sp1(new int);
    ShardPtr<int> sp2(new int);
    cout << div() << endl;
}

int main()
{
    try {
        Func();
    }
    catch (const exception& e)
    {
        cout << e.what() << endl;
    }
    return 0;
}


// 特殊类设计
